﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data.SqlClient;
using DBWTProject.persistence;
using DBWTProject.models;
using System.Text;
using System.Globalization;
using System.Reflection;

namespace DBWTProject.route
{
    public partial class Stat : System.Web.UI.Page
    {
        public int Year { get; set; }

        private ISet<MonthStatistic> _monthStatisticList = new SortedSet<MonthStatistic>();

        protected void Page_Load(object sender, EventArgs e)
        {
            User user = (User)Session[Constants.SESSIONVAR_CURRENTUSER];
            if (user == null)
            {//nicht eingeloggt
                Response.Redirect("/");
                return;
            }

            String yearString = Request.QueryString["y"];
            // kein notwendiger Parameter übergeben
            if (String.IsNullOrEmpty(yearString))
            {
                Response.Redirect("/");
                return;
            }
            Year = Convert.ToInt32(yearString);

            dlYear.DataSource = RouteDAO.GetYearsWithRoutes(user);
            dlYear.DataBind();

            //Month-Statistiken erstellen, in separate Struktur überführen, da ich es an zwei verschiedenen Stellen wieder benötige.
            IList<int> monthList = RouteDAO.GetMonthsWithAvailableRoutes(Year, user);
            double distance, duration, elevation, meanSpeedReally;
            DateTime dateBegin, dateEnd;
            IList<Route> routes;
            foreach (int month in monthList)
            {
                dateBegin = new DateTime(Year, month, 1);
                dateEnd = new DateTime(Year, month, 1).AddMonths(1).AddDays(-1);
                routes = RouteDAO.GetRoutes(user, dateBegin, dateEnd, null);
                CalculateSummaryCharacteristics(routes, out distance, out duration, out elevation, out meanSpeedReally);
                _monthStatisticList.Add(new MonthStatistic()
                {
                    Month = month,
                    Distance = distance,
                    Duration = duration,
                    Elevation = elevation,
                    MeanSpeed = meanSpeedReally,
                    Routes = routes
                });
            }
        }

        public string OutputHTML()
        {
            StringBuilder sb = new StringBuilder();
            User user = (User)Session[Constants.SESSIONVAR_CURRENTUSER];

            //Erstmal gesamt für Jahr
            DateTime dateBegin, dateEnd;
            dateBegin = new DateTime(Year, 1, 1);
            dateEnd = new DateTime(Year, 12, 31);
            IList<Route> routes = RouteDAO.GetRoutes(user, dateBegin, dateEnd, null);
            double distance, duration, elevation, meanSpeedReally;
            CalculateSummaryCharacteristics(routes, out distance, out duration, out elevation, out meanSpeedReally);
            AppendTable(sb, Year.ToString(), routes.Count, distance, duration, elevation, meanSpeedReally, false);

            //Jetzt für Monate
            foreach (MonthStatistic monthStat in _monthStatisticList)
            {
                AppendTable(sb, Year + "/" + monthStat.Month, monthStat.Routes.Count, monthStat.Distance, monthStat.Duration, monthStat.Elevation, monthStat.MeanSpeed, true);
            }
            sb.AppendLine("<br style='clear:both;'/>");
            return sb.ToString();
        }

        /// <summary>
        /// Wrapper-Objekt zum Halten der Monatsauswertungen.
        /// </summary>
        class MonthStatistic : IComparable
        {
            public int Month { get; set; }
            public IList<Route> Routes { get; set; }
            public double Distance { get; set; }
            public double Duration { get; set; }
            public double Elevation { get; set; }
            public double MeanSpeed { get; set; }

            public int CompareTo(object obj)
            {
                return Month.CompareTo(((MonthStatistic)obj).Month);
            }
        }

        /// <summary>
        /// Errechnet die SummaryCharateristics. Beachtet out-paras.
        /// </summary>
        /// <param name="routes"></param>
        /// <param name="distance"></param>
        /// <param name="elevation"></param>
        /// <param name="meanSpeedReally"></param>
        private static void CalculateSummaryCharacteristics(IList<Route> routes, out double distance, out double duration, out double elevation, out double meanSpeedReally)
        {
            distance = 0;
            elevation = 0;
            duration = 0;
            double meanSpeed = 0;
            Int32 c = 0;
            foreach (Route item in routes)
            {
                distance += item.Distance;
                duration += item.DurationInHours;
                elevation += item.Elevation;

                if (!Double.IsNaN(item.MeanSpeed))
                {
                    meanSpeed += item.MeanSpeed;
                    c++;
                }
            }
            meanSpeedReally = meanSpeed / c;
        }

        /// <summary>
        /// Fügt HTML-Tabelle mit werten an StringBuilder an.
        /// </summary>
        /// <param name="sb"></param>
        /// <param name="title"></param>
        /// <param name="distance"></param>
        /// <param name="elevation"></param>
        /// <param name="meanSpeedReally"></param>
        private static void AppendTable(StringBuilder sb, string title, int routeCount, double distance, double duration, double elevation, double meanSpeedReally, bool floatLayout)
        {
            if (floatLayout)
            {
                sb.AppendLine("<div style='float:left; margin-left:10px;'>");
            }

            sb.AppendLine("<h3>" + title + "</h3>");
            sb.AppendLine("<table class='datatable'><tr><th>Characteristic</th><th>Value</th></tr>");
            sb.AppendLine("<tr><td>Route count:</td>");
            sb.AppendLine("<td>" + routeCount + "&nbsp; routes</td></tr>");

            sb.AppendLine("<tr><td>Total distance:</td>");
            sb.AppendLine("<td>" + distance.ToString("0.0") + "&nbsp;km</td></tr>");

            sb.AppendLine("<tr><td>Total duration:</td>");
            sb.AppendLine("<td>" + duration.ToString("0.0") + "&nbsp;h</td></tr>");

            sb.AppendLine("<tr><td>Total elevation covered:</td>");
            sb.AppendLine("<td>" + elevation.ToString("0.0") + "&nbsp;m</td></tr>");

            sb.AppendLine("<tr><td>Mean speed:</td>");
            sb.AppendLine("<td>" + meanSpeedReally.ToString("0.0") + "&nbsp;km/h</td></tr>");
            sb.AppendLine("</table>");
            if (floatLayout)
            {
                sb.AppendLine("</div>");
            }
        }

        /// <summary>
        /// Printet DataTable für GoogleVisualization aus.
        /// </summary>
        /// <param name="propertyName"></param>
        /// <returns></returns>
        public string GetDataTableForMonthCompare(string propertyName)
        {
            CultureInfo cultureInfoUS = new CultureInfo("en-US", false);
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("[");

            //['Characteristic', '2006/1', '2006/4', '2006/9'],
            sb.Append("['Characteristic', ");
            foreach (MonthStatistic monthStat in _monthStatisticList)
            {
                sb.Append("'");
                sb.Append(Year + "/" + monthStat.Month);
                sb.Append("',");
            }
            sb.AppendLine("],");

            //['Total distance', 1000, 400, 800],
            sb.Append("['" + propertyName + "', ");
            PropertyInfo property = typeof(MonthStatistic).GetProperty(propertyName);
            foreach (MonthStatistic monthStat in _monthStatisticList)
            {
                double value = (double)property.GetValue(monthStat, null);
                sb.Append(value.ToString("0.0", cultureInfoUS));
                sb.Append(",");
            }
            sb.AppendLine("],");

            sb.AppendLine("]");
            return sb.ToString();
        }
    }
}